package com.scs.application.core.aliyun.oss.handler;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.*;
import com.scs.application.core.aliyun.oss.core.OssCallback;
import com.scs.application.core.aliyun.oss.properties.AliyunOssProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.*;

@Slf4j
@AllArgsConstructor
public class AliyunOssHandler {

    @Autowired
    private AliyunOssProperties aliyunOssProperties;
    private ThreadPoolExecutor executor;

    public AliyunOssHandler() {
        this.executor = new ThreadPoolExecutor(0, 10, 60L, TimeUnit.SECONDS, new SynchronousQueue());
    }

    public void setExecutor(ThreadPoolExecutor executor) {
        this.executor = executor;
    }

    private OSS createClient() {
        ClientConfiguration config = new ClientConfiguration();
        if (this.aliyunOssProperties.isSecure()) {
            config.setProtocol(Protocol.HTTPS);
        } else {
            config.setProtocol(Protocol.HTTP);
        }

        OSS ossClient = new OSSClient(this.aliyunOssProperties.getEndpoint(), this.aliyunOssProperties.getAccessKeyId(), this.aliyunOssProperties.getAccessKeySecret(), config);
        return ossClient;
    }

    public <T> T execute(OssCallback<T> action) {
        OSS ossClient = this.createClient();

        T var3;
        try {
            var3 = action.execute(ossClient);
        } finally {
            ossClient.shutdown();
        }

        return var3;
    }

    public byte[] readBytes(String path) throws IOException {
        OSS ossClient = this.createClient();
        BufferedInputStream bis = null;

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Throwable var5 = null;

            try {
                OSSObject ossObject = ossClient.getObject(this.aliyunOssProperties.getBucketName(), path);
                byte[] bytes;
                if (ossObject == null) {
                    bytes = new byte[0];
                    return bytes;
                } else {
                    bis = new BufferedInputStream(ossObject.getObjectContent());
                    bytes = new byte[1024];

                    while(true) {
                        int len = bis.read(bytes, 0, bytes.length);
                        if (len == -1) {
                            byte[] var29 = baos.toByteArray();
                            return var29;
                        }

                        baos.write(bytes, 0, len);
                    }
                }
            } catch (Throwable var26) {
                var5 = var26;
                throw var26;
            } finally {
                if (baos != null) {
                    if (var5 != null) {
                        try {
                            baos.close();
                        } catch (Throwable var25) {
                            var5.addSuppressed(var25);
                        }
                    } else {
                        baos.close();
                    }
                }

            }
        } finally {
            ossClient.shutdown();
            if (bis != null) {
                bis.close();
            }

        }
    }

    public String getSignUrl(String filePath, Date expiration) {
        return this.getSignUrl(filePath, expiration, (String)null);
    }

    public String getSignUrl(String filePath, Date expiration, String style) {
        return (String)this.execute((ossClient) -> {
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(this.aliyunOssProperties.getBucketName(), filePath, HttpMethod.GET);
            req.setExpiration(expiration);
            req.setProcess(style);
            URL url = ossClient.generatePresignedUrl(req);
            return url.toString();
        });
    }

    public void localFileUpload(File file, String dir, String fileName) {
        this.execute((ossClient) -> {
            return ossClient.putObject(this.aliyunOssProperties.getBucketName(), dir + fileName, file);
        });
    }

    public void inputStreamUpload(InputStream is, String dir, String fileName) {
        this.inputStreamUpload(is, dir, fileName, (ObjectMetadata)null);
    }

    public void inputStreamUpload(InputStream is, String dir, String fileName, ObjectMetadata metadata) {
        this.execute((ossClient) -> {
            return ossClient.putObject(this.aliyunOssProperties.getBucketName(), dir + fileName, is, metadata);
        });
    }

    public List<OSSObjectSummary> listObjects() {
        return (List)this.execute((ossClient) -> {
            String nextMarker = null;
            String bucketName = this.aliyunOssProperties.getBucketName();
            ArrayList result = new ArrayList();

            ObjectListing objectListing;
            do {
                objectListing = ossClient.listObjects((new ListObjectsRequest(bucketName)).withMarker(nextMarker).withMaxKeys(200));
                List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
                result.addAll(sums);
                nextMarker = objectListing.getNextMarker();
            } while(objectListing.isTruncated());

            return result;
        });
    }

    public SimplifiedObjectMeta getSimplifiedObjectMeta(String objectName) {
        return (SimplifiedObjectMeta)this.execute((ossClient) -> {
            return ossClient.getSimplifiedObjectMeta(this.aliyunOssProperties.getBucketName(), objectName);
        });
    }

    public ObjectMetadata getObjectMetadata(String objectName) {
        return (ObjectMetadata)this.execute((ossClient) -> {
            return ossClient.getObjectMetadata(this.aliyunOssProperties.getBucketName(), objectName);
        });
    }

    public OSS getOssClient() {
        OSS ossClient = this.createClient();
        return ossClient;
    }

    public void multipartFileUpload(MultipartFile file) throws IOException {
        OSS ossClient = this.createClient();
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(this.aliyunOssProperties.getBucketName(), file.getOriginalFilename());
        InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);
        String uploadId = result.getUploadId();
        long partSize = 52428800L;
        long fileLength = file.getSize();
        int partCount = (int)(fileLength / partSize);
        if (fileLength % partSize != 0L) {
            ++partCount;
        }

        List<Future<UploadPartResult>> tasks = new ArrayList();

        for(int i = 0; i < partCount; ++i) {
            long startPos = (long)i * partSize;
            int partIndex = i + 1;
            long curPartSize = partIndex == partCount ? fileLength - startPos : partSize;
            InputStream instream = file.getInputStream();
            instream.skip(startPos);
            Future<UploadPartResult> submit = this.executor.submit(() -> {
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(this.aliyunOssProperties.getBucketName());
                uploadPartRequest.setKey(file.getOriginalFilename());
                uploadPartRequest.setUploadId(uploadId);
                uploadPartRequest.setInputStream(instream);
                uploadPartRequest.setPartSize(curPartSize);
                uploadPartRequest.setPartNumber(partIndex);
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
                return uploadPartResult;
            });
            tasks.add(submit);
        }

        this.executor.submit(() -> {
            List<PartETag> partETags = new ArrayList();
            Iterator iterator = tasks.iterator();

            while(iterator.hasNext()) {
                Future task = (Future)iterator.next();

                try {
                    partETags.add(((UploadPartResult)task.get()).getPartETag());
                } catch (InterruptedException var9) {
                    var9.printStackTrace();
                } catch (ExecutionException var10) {
                    var10.printStackTrace();
                }
            }

            Collections.sort(partETags, Comparator.comparingInt(PartETag::getPartNumber));
            CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(this.aliyunOssProperties.getBucketName(), file.getOriginalFilename(), uploadId, partETags);
            ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            ossClient.shutdown();
        });
    }
}

